#include <cstdio>
#include <vector>
#include <algorithm>
#include <set>
#include <map>

using namespace std;

long long read(){
    long long x = 0; int zf = 1; char ch = ' ';
    while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    if (ch == '-') zf = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * zf;
}

namespace Qpow{
	long long pow(long long a, long long b, long long mod){
		if (!a) return 0;
		long long res = 1; a %= mod;
		for ( ; b; (a *= a) %= mod, b >>= 1ll)
			if (b & 1) (res *= a) %= mod;;
		return res;
	}
};

//build
struct Node{
    int l, r;
    mutable long long val;
    Node(int a = -1, int b = -1, long long c = 0){
        l = a, r = b, val = c;
    }
    bool operator < (const Node &a) const{
        return l < a.l;
    }
};

set<Node> st;

//modify
set<Node>::iterator split(int pos){
    set<Node>::iterator it = st.lower_bound(Node(pos));
    if (it != st.end() && it->l == pos) return it;
    --it; Node tmp = *it; st.erase(it);
    st.insert(Node(tmp.l, pos - 1, tmp.val));
    return st.insert(Node(pos, tmp.r, tmp.val)).first; //first return iterator
}

void assign(int l, int r, long long val){
	set<Node>::iterator itr = split(r + 1), itl = split(l);
    st.erase(itl, itr);
    st.insert((Node){l, r, val});
}

void add(int l, int r, long long val){
    set<Node>::iterator itr = split(r + 1), itl = split(l);
    for (set<Node>::iterator it = itl; it != itr; ++it)
        it->val += val;
}

//query
long long querySum(int l, int r){
    set<Node>::iterator itr = split(r + 1), itl = split(l); long long res = 0;
    for (set<Node>::iterator it = itl; it != itr; ++it)
        res += (it->r - it->l + 1) * it->val;
    return res;
}

long long querySumWithPow(int l, int r, long long x, long long mod){
    set<Node>::iterator itr = split(r + 1), itl = split(l); long long res = 0;
    for (set<Node>::iterator it = itl; it != itr; ++it)
        (res += (it->r - it->l + 1) * Qpow::pow(it->val, x, mod)) %= mod;
    return res;
}

long long queryKth(int l, int r, int k){
    vector< pair<long long, int> > vec(0);
    set<Node>::iterator itr = split(r + 1), itl = split(l);
    for (set<Node>::iterator it = itl; it != itr; ++it)
        vec.push_back(make_pair(it->val, it->r - it->l + 1));
    sort(vec.begin(), vec.end());
    for (vector< pair<long long, int> >::iterator it = vec.begin(); it != vec.end(); ++it)
        if ((k -= it->second) <= 0) return it->first;
    return -1; //note:if there are negative numbers, return another impossible number.
}

long long seed;
long long a[100005];

inline long long rnd(){
	long long ret = seed; seed = (seed * 7 + 13) % 1000000007;
	return ret;
}

int main(){
	int n = read(), m = read(); seed = read(); long long vmax = read();
	for (int i = 1; i <= n; ++i){
		a[i] = (rnd() % vmax) + 1;
		st.insert((Node){i, i, a[i]});
	}
	long long x, y;
	for (int i = 1; i <= m; ++i){
	    int op = (rnd() % 4) + 1, l = (rnd() % n) + 1, r = (rnd() % n) + 1;
	    if (l > r){int tmp = l; l = r, r = tmp;}
	    if (op == 3)
	        x = (rnd() % (r - l + 1)) + 1;
	    else
	        x = (rnd() % vmax) + 1;
	    if (op == 4)
	        y = (rnd() % vmax) + 1;
	    if (op == 1) add(l, r, x);
	    else if (op == 2) assign(l, r, x);
	    else if (op == 3) printf("%I64d\n", queryKth(l, r, x));
	    else if (op == 4) printf("%I64d\n", querySumWithPow(l, r, x, y));
	}
    return 0;
}